<?php

final class Loader {

    protected $registry;

    public function __construct() {
        $this->registry = Registry::getInstance();
        
        $this->init_blocks();
       
        $this->init_modules();
        
        $this->init_themes();

    }

    /**
     *
     * @param type $view
     *  view которую необходимо подключить, если она уже была подключена,
     *  ничего оне происходит.
     * @return type
     */
    /* public function view($view) {

      $file = 'class.' . $view . 'View.php';

      if (in_array($file, $this->registry->includedfiles))
      return;

      foreach (new DirectoryIterator(DIR_APPLICATION) as $dir) {
      if ($dir->isDot() || $dir->isFile() || $dir->getBasename() == '.svn')
      continue;
      foreach (new DirectoryIterator($dir->getPath() . "/" . $dir->getBasename() . '/View') as $dir2) {
      if ($dir2->isDot())
      continue;
      if ($dir2->isFile()) {
      if ($dir2->getBasename() == $file) {
      $this->registry->set('includedfiles', array_merge($this->registry->includedfiles, array($file)));
      require_once $dir2->getPath() . '/' . $dir2->getBasename();
      return;
      }
      }
      }
      }
      trigger_error('Error: Could not load view ' . $view . '!');
      exit();
      }

      public function controller($path) {
      require_once $path;
      } */

    public function init_themes() {
        
        $themes_data = array();
        // папка тем
        $iter = new DirectoryIterator(DIR_TEMPLATES);
            foreach ($iter as $dir_theme) {
                if ($dir_theme->isDot() || $dir_theme->getBasename() == '.svn')
                    continue;
                
                if ($dir_theme->isDir()) {
                    $fp = fopen(DIR_TEMPLATES.$dir_theme->getBasename() . '/template.info', 'r');

                    while (!feof($fp)) {
                        $str = fgets($fp);
                        //echo $str . '<br>';
                        if ($str[0] != "#" && trim($str) != "") {
                            $parts = explode(':', $str);
                            $right_parts = explode(',', $parts[1]);
                            foreach ($right_parts as $key => $value)
                            {
                               $right_parts[$key] = trim($value);
                            }
                            $themes_data[$dir_theme->getBasename()][trim($parts[0])] = $right_parts;
                        }
                    } 
                    fclose($fp);
                }
            }

            
        $this->registry->set('themes', $themes_data);
//        echo"<pre>";
//        var_dump($themes_data);
//        echo"</pre>";
        return $themes_data;  
    }

    public function library($library, $module = 'core') {

        if ($module == 'core')
            $file = DIR_SYSTEM . 'lib/class.' . $library . '.php';
        else
            $file = $this->registry->modules[$module]['path'] . '/lib/' . $library;

        if (is_dir($file)) {
            $iter = new DirectoryIterator($file);
            foreach ($iter as $dir_lib) {
                if ($dir_lib->isFile()) {
                    $path = $dir_lib->getPath().'/'.$dir_lib->getFilename();
                    if (file_exists($path)) {
                        $this->registry->set('includedfiles', array_merge($this->registry->includedfiles, array($dir_lib)));
                        include_once($path);
                    } else {
                        trigger_error('Error: Could not load library ' . $path . '!!');
                        exit();
                    }
                }
            }

        } else {
            if (in_array($file, $this->registry->includedfiles))
                return;
            if (file_exists($file)) {
                $this->registry->set('includedfiles', array_merge($this->registry->includedfiles, array($file)));
                include_once($file);
            } else {
                trigger_error('Error: Could not load library ' . $library . '!');
                exit();
            }
        }
    }

    /*
      public function model($model) {

      $file = 'class.' . $model . 'Model.php';
      $class = preg_replace('/[^a-zA-Z0-9]/', '', $model) . 'Model';

      if (isset($this->registry->{'model_' . $model}))
      return;

      $flag = false;
      foreach (new DirectoryIterator(DIR_APPLICATION) as $dir) {
      if ($dir->isDot() || $dir->isFile() || $dir->getBasename() == '.svn')
      continue;
      foreach (new DirectoryIterator($dir->getPath() . "/" . $dir->getBasename() . '/Model') as $dir2) {
      if ($dir2->isDot())
      continue;
      if ($dir2->isFile()) {
      if ($dir2->getBasename() == $file) {
      require_once $dir2->getPath() . '/' . $dir2->getBasename();
      $flag = false;
      break;
      }
      }
      }
      if ($flag)
      break;
      }
      $this->registry->set('model_' . $model, new $class($this->registry));
      } */

    /**
     * Загружает все компоненты из папки компонентов 
     */
    public function init_blocks() {
        $this->registry->set('blocks', array());
        $blocks_data = array();
        // папка компонентов
        $iter = new DirectoryIterator(DIR_BLOCKS);
        foreach ($iter as $dir_places) {

            if ($dir_places->isDot() || $dir_places->getBasename() == '.svn')
                continue;

            foreach (new DirectoryIterator($dir_places->getPath() . "/" . $dir_places->getBasename() . '') as $dir_blocks) {
                if ($dir_blocks->isDot() || $dir_blocks->getBasename() == '.svn')
                    continue;
                if ($dir_blocks->isDir()) {

                    $fp = fopen($dir_places->getPath() . "/" . $dir_places->getBasename() . '/' . $dir_blocks->getBasename() . '/info.cfg', 'r');

                    $block_paths_to_mvc = array();
                    $block_info = array();

                    while (!feof($fp)) {
                        $str = fgets($fp);
                        //echo $str . '<br>';
                        if ($str[0] != "#" && trim($str) != "") {

                            if (preg_match('/^((?:CONTROLLERS)|(?:MODELS)|(?:VIEWS)):([\D]+)$/ui', $str, $res)) {
                                //$res[1] - название (CONTROLLER|VIEWS|MODELS)
                                //$res[2] - пути до классов
                                $paths = array();
                                $paths = explode(',', $res[2]);
                                foreach ($paths as $key => $path) {
                                    $path = trim($path);
                                    if (!empty($path))
                                        $paths[$key] = $dir_places->getBasename() . '/' . $dir_blocks->getBasename() . '/' . $path;
                                }
                                $block_paths_to_mvc[strtolower($res[1])] = $paths;
                            }
                            if (preg_match('/^((?:MACHINE-NAME)|(?:VERSION)|(?:MAIN-CONTROLLER)):\s*([\w\s\d.]+\s*)$/ui', $str, $res)) {
                                //$res[1] - название переменной
                                //$res[2] - пути до классов
                                $value = trim($res[2]);

                                if (empty($value)) {
                                    trigger_error('Block data not found! - ' . trim(strtolower($res[1])) . '!');
                                    exit();
                                }
                                $key = trim(strtolower($res[1]));
                                $block_info[trim(strtolower($res[1]))] = ($key != 'main-controller' ? strtolower($value) : $value);
                            }
                        }
                    }

                    fclose($fp);
                }
                if (!isset($block_info['machine-name'])) {
                    trigger_error('Machine name not found for block!');
                    exit();
                }
                $blocks_data[$block_info['machine-name']] = $block_info;
                $blocks_data[$block_info['machine-name']]['mvc'] = $block_paths_to_mvc;

                unset($blocks_data[$block_info['machine-name']]['machine-name']);
                $this->registry->blocks = array_merge($blocks_data, $this->registry->blocks);
                $this->block($block_info['machine-name']);
            }
        }
       
        return $blocks_data;
    }

    public function block($machine_name) {

        $blocks = $this->registry->blocks;

        if (empty($blocks)) {
            trigger_error('Components not init');
            exit();
        }

        if (!isset($blocks[$machine_name])) {
            trigger_error('Component not found');
            exit();
        }

        $block = $this->registry->blocks[$machine_name];

//        echo '<pre>'; var_dump($this->registry->blocks); echo '</pre>'; 

        foreach ($block['mvc']['controllers'] as $controller) {
            if (file_exists(DIR_BLOCKS . $controller))
                require_once DIR_BLOCKS . $controller;
            else {
                trigger_error("Controller of " . $machine_name . " does not exists");
                exit();
            }
        }

        foreach ($block['mvc']['models'] as $model) {
            if (file_exists(DIR_BLOCKS . $model))
                require_once DIR_BLOCKS . $model;
//            else
//            {
//                trigger_error("Model of " . $machine_name .  " does not exists");
//                //exit();
//            }
        }


        foreach ($block['mvc']['views'] as $view) {
            if (file_exists(DIR_BLOCKS . $view))
                require_once DIR_BLOCKS . $view;
//            else
//            {
//                trigger_error("View of " . $machine_name .  " does not exists");
//                exit();
//            }
        }

//        foreach($block['mvc'] as $mvc)
//        {
//            foreach($mvc as $item)
//            {
//                require_once DIR_BLOCKS . $item;
//            }
//        }
    }

    /**
     * Загружает все включенные модули
     */
    public function init_modules() {
        $modules_data = array();

        $cfg = $this->registry->get('config');
        $iter = new DirectoryIterator(DIR_MODULES);
        foreach ($iter as $dir_owner) {

            if ($dir_owner->isDot() || $dir_owner->getBasename() == '.svn')
                continue;
            
            if ($dir_owner->isDir()) {
                
                $iterb = new DirectoryIterator($dir_owner->getPath() . "/" . $dir_owner->getBasename() . '');
                
                foreach ($iterb as $dir_modules) {
                    
                    if ($dir_modules->isDot() || $dir_modules->getBasename() == '.svn')
                        continue;
                    
                    $modules_mvc = array('controller' => array(), 'view' => array(), 'model' => array());
                    $hooks = array();
                    
                    if (in_array($dir_modules, $cfg['defmodules']) || in_array($dir_modules, $cfg['usermodules'])) {
                        $itera = new DirectoryIterator($dir_modules->getPath() . "/" . $dir_modules->getBasename() . '');
                        foreach ($itera as $dir_mvc) {
                            if ($dir_mvc->isDot() || $dir_mvc->getBasename() == '.svn')
                                continue;
                            
                           
                            if ($dir_mvc->isDir() && in_array($dir_mvc, array('Controller', 'Model', 'View'))) {
                                
                                $iterc = new DirectoryIterator($dir_mvc->getPath() . "/" . $dir_mvc->getBasename() . '');
                                foreach ($iterc as $classname) {
                                    //echo $classname->getBaseName() . "<br>";
                                    if ($classname->isFile() && preg_match('/^(class).([a-z_A-Z]+).(php)$/', $classname, $matches) && file_exists($classname->getPath() . '/' . $classname->getBaseName())) {
                                        
                                        require_once ($classname->getPath() . '/' . $classname->getBaseName());
                                        $methods = get_class_methods($matches[2]);
//                                        echo $matches[2].'<br>';
                                        $methods = array_filter($methods, function ($item) use (&$methods) {
                                                    $pair = each($methods);
                                                    return preg_match('/^(hook)_([a-z_A-Z]+)$/', $pair[1]);
                                                });
                                        $hooks[$matches[2]] = $methods;
//                                        echo '<pre>';
//                                        var_dump($methods);
//                                        echo '</pre>';

                                        $this->registry->set('includedfiles', array_merge($this->registry->includedfiles, array($classname->getBaseName())));
                                        $modules_mvc[strtolower($dir_mvc->getBasename())][] = $classname->getPath() . '/' . $classname->getBasename();
//                                 echo '<pre>';
//                                var_dump($modules_mvc);
//                                echo '</pre>';
                                        $modules_data[strtolower($dir_modules->getBasename())]['path'] = $dir_mvc->getPath();
                                        $modules_data[strtolower($dir_modules->getBasename())]['mvc'] = $modules_mvc;
                                        $modules_data[strtolower($dir_modules->getBasename())]['hooks'] = $hooks;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        $this->registry->set('modules', $modules_data);
//        echo '<pre>'; var_dump($modules_data); echo '</pre>'; 
    }

}

?>